import name.fowler.refactoring.simplestore.domain.JPAEntity;

import javax.persistence.*;
import java.util.List;
import java.util.Map;

/**
 * User: RedSmog
 * Date: 19.10.13
 * Time: 17:48
 */

public class Crud implements AutoCloseable {

    private EntityManager em;

    public Crud(EntityManager em) {
        em.getTransaction().begin();
        this.em = em;
    }

    public void create(JPAEntity entity) {
        em.persist(entity);
    }

    public <T extends JPAEntity> List<T> readAll(Class<T> clazz) {
        return readAll(clazz, LockModeType.OPTIMISTIC);
    }

    public <T extends JPAEntity> List<T> readAll(Class<T> clazz, LockModeType lockModeType) {
        return readAll(clazz, lockModeType, null);
    }


    public <T extends JPAEntity> List<T> readAll(Class<T> clazz, LockModeType lockModeType, Map<String, Object> properties) {
        String entityName = em.getMetamodel().entity(clazz).getName();
        TypedQuery<T> query = em.createQuery(String.format("select c from %s c", entityName), clazz);
        if (properties != null) {
            for (Map.Entry<String, Object> property : properties.entrySet()) {
                query.setHint(property.getKey(), property.getValue());
            }
        }
        query.setLockMode(lockModeType);
        return query.getResultList();
    }

    public <T extends JPAEntity> T update(T entity) {
        return  em.merge(entity);
    }

    public void delete(JPAEntity entity) {
        em.remove(entity);
    }

    public <T extends JPAEntity> int delete(Class<T> clazz, int id) {
        String entityName = em.getMetamodel().entity(clazz).getName();
        Query query = em.createQuery(String.format("delete from %s c where c.id = :id", entityName));
        query.setParameter("id", id);
        return query.executeUpdate();
    }

    public void lock(JPAEntity entity, LockModeType lockModeType) {
        em.lock(entity, lockModeType);
    }

    public void flush() {
        em.flush();
    }

    public void commit() {
        em.getTransaction().commit();
    }

    public void rollback() {
        em.getTransaction().rollback();
    }

    @Override
    public void close() {
        em.close();
    }
}
